home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
031-040
/
amok31
/
boothandler
/
boothandler.mod
< prev
next >
Wrap
Text File
|
1993-11-04
|
14KB
|
529 lines
(*---------------------------------------------------------------------------
:Program. BootHandler.mod
:Contents. Dies ist ein Dos-Handler, der Bootblöcke als Files simuliert
:Author. Bernd Preusing
:Address. Gerhardstr. 16 D-2200 Elmshorn
:Phone. 04121/22486
:Copyright. Public Domain
:Language. Modula-2
:Translator. M2Amiga V3.2e
:Support. nach 'Amiga 9/89' Seite 118ff aus C übersetzt und Fehler raus.
:History. 1.0 02-Sep-89 Bernd Preusing
:Imports. DosSupport [bne]
:Bugs. NICHT reentrant! (hat bis jetzt noch nicht gestört)
:Bugs. nicht SEHR getestet!
:Remark. Benutzt sehr viel BPOINTER und BPTR!
:Remark. Dies ist kein normales Programm, sondern ein Handler!!
:Remark. Es muß 'l:Boot-Handler' heißen! Siehe Dokumentation!
:Usage. 'mount BOOT:' dann z.B. 'copy boot:df0 boot:dh29'
---------------------------------------------------------------------------*)
MODULE BootHandler;
FROM SYSTEM IMPORT CAST, ADDRESS, BPTR, LONGSET, ADR, SETREG;
FROM Arts IMPORT TermProcedure, wbStarted, startupMsg;
IMPORT Exec;
FROM Exec IMPORT MsgPortPtr, WaitPort, PutMsg, MessagePtr,
Node, NodePtr, List, ListPtr, UByte,
MemReqs, MemReqSet, Task,
IOStdReqPtr, AllocMem, FreeMem, OpenDevice, CloseDevice,
AddTail, Remove, Wait, GetMsg, DoIO, FindTask;
IMPORT Dos;
FROM Dos IMPORT readWrite, oldFile, newFile, beginning, current,
end, sharedLock, exclusiveLock, BSTR, FileHandlePtr,
FileLockPtr, DosLibraryPtr, DosPacketPtr,
objectInUse, actionNotKnown, deviceNotMounted,
invalidLock, FileLock,
freeLock, locateObject, examineObject,
seekError, deleteProtected, read, write, currentVolume,
flush, deleteObject, objectNotFound, writeProtected,
ProcessPtr, DosPacket, DeviceListType, DeviceListPtr,
FileSysStartupMsgPtr, EnvironmentPtr, sizeBlock,
reservedBlocks, memBufType, lowCyl,
blksPerTrack, numHeads,
FileInfoBlock, FileInfoBlockPtr, ProtectionFlags,
ProtectionFlagSet;
FROM ExecSupport IMPORT NewList, CreatePort, DeletePort, CreateStdIO,
DeleteStdIO;
FROM DosSupport IMPORT BSTRtoStr;
CONST
FNSIZE = 128;
ACTIONEND = 1007;
ACTIONSEEK = 1008;
DOSTRUE = -1;
DOSFALSE = 0;
TYPE
CharPtr = POINTER TO CHAR;
UnitData = RECORD
node: Node;
port: MsgPortPtr;
request: IOStdReqPtr;
unitSize: LONGINT;
access: LONGINT;
udOffset,
buf,
pos,
udEnd: LONGINT; (* sonst end doppelt bei WITH *)
END;
UnitDataPtr = POINTER TO UnitData;
(* $R- $S- $V- $F- *)
PROCEDURE Cleanup;
BEGIN
SETREG(0,Wait(LONGSET{})); (* never return!!!!!!!! *)
END Cleanup;
PROCEDURE StrICmp(a,b:CharPtr):BOOLEAN;
BEGIN
WHILE (CAP(a^)=CAP(b^)) AND (a^#0C) DO
INC(a); INC(b);
END;
RETURN (a^=0C) AND (b^=0C)
END StrICmp;
PROCEDURE strlen(p:CharPtr):LONGINT;
VAR l:LONGINT;
BEGIN
l:=0;
WHILE p^#0C DO INC(p); INC(l) END;
RETURN l;
END strlen;
PROCEDURE StrCpy(to,from:CharPtr);
BEGIN
DEC(to); DEC(from);
REPEAT
INC(to); INC(from);
to^:=from^;
UNTIL to^=0C;
END StrCpy;
PROCEDURE ReturnPacket(packet:DosPacketPtr; sender:ProcessPtr);
VAR mp: MsgPortPtr;
BEGIN
WITH packet^ DO
mp:=port;
WITH link^.node DO
name:=packet;
succ:=NIL;
pred:=NIL;
END;
port:=ADR(sender^.msgPort);
PutMsg(mp,link);
END;
END ReturnPacket;
PROCEDURE WaitPacket(rec:ProcessPtr):DosPacketPtr;
TYPE WaitProc = PROCEDURE():MessagePtr;
VAR msg: MessagePtr;
PKTWAIT: WaitProc;
BEGIN
(* PKTWAIT:=CAST(WaitProc,rec^.pktWait);
IF CAST(LONGINT,PKTWAIT)#0 THEN
msg:=PKTWAIT()
ELSE *)
WaitPort(ADR(rec^.msgPort));
msg:=GetMsg(ADR(rec^.msgPort));
(* END;*)
RETURN CAST(DosPacketPtr,msg^.node.name)
END WaitPacket;
PROCEDURE FindAccessConflict(VAR list:List;name:ADDRESS;mode:LONGINT):BOOLEAN;
VAR node: UnitDataPtr;
BEGIN
node:=CAST(UnitDataPtr,list.head);
WHILE CAST(NodePtr,node)#node^.node.succ DO
IF StrICmp(node^.node.name,name) AND (node^.access=mode) THEN
RETURN TRUE
END;
node:=CAST(UnitDataPtr,node^.node.succ);
END;
RETURN FALSE;
END FindAccessConflict;
PROCEDURE DoDeviceCmd(unit:UnitDataPtr;cmd:CARDINAL):LONGINT;
BEGIN
WITH unit^ DO
WITH request^ DO
offset:=udOffset;
data:=buf;
length:=udEnd;
command:=cmd;
END;
DoIO(request);
END;
IF unit^.request^.error#0 THEN
SETREG(0,DoDeviceCmd(unit,Exec.clear));
RETURN DOSTRUE
ELSE
RETURN unit^.request^.actual
END;
END DoDeviceCmd;
PROCEDURE DoDiskCmd(unit:UnitDataPtr; cmd:CARDINAL; baf:CharPtr;
length:LONGINT):LONGINT;
VAR i:LONGINT;
act:CharPtr;
BEGIN
WITH unit^ DO
IF length>udEnd-pos THEN
length:=udEnd-pos
END;
IF length>0 THEN
IF cmd=Exec.read THEN
IF DoDeviceCmd(unit,Exec.read)=udEnd THEN
act:=CAST(CharPtr,buf+pos);
FOR i:=0 TO length-1 DO
baf^:=act^;
INC(baf); INC(act);
END;
INC(pos,length);
ELSE
length:=DOSTRUE;
act:=CAST(CharPtr,buf);
FOR i:=0 TO udEnd-1 DO
act^:=0C; INC(act);
END;
pos:=udEnd;
END;
ELSIF cmd=Exec.write THEN
act:=CAST(CharPtr,buf+pos);
FOR i:=0 TO length-1 DO
act^:=baf^;
INC(act); INC(baf);
END;
IF (DoDeviceCmd(unit,Exec.write)=DOSTRUE) OR
(DoDeviceCmd(unit,Exec.update)=DOSTRUE) THEN
length:=DOSTRUE;
ELSE
INC(pos,length);
END;
ELSE
length:=DOSTRUE;
END;
END;
END;
RETURN length;
END DoDiskCmd;
PROCEDURE CloseDiskDevice(unit:UnitDataPtr; arg:INTEGER);
BEGIN
WITH unit^ DO
IF arg<=0 THEN
FreeMem(buf,udEnd);
END;
IF arg<=1 THEN
request^.length:=0;
request^.command:=Exec.nonstd;
DoIO(request);
CloseDevice(request);
END;
IF arg<=2 THEN
DeleteStdIO(request);
END;
IF arg<=3 THEN
DeletePort(port);
END;
IF arg<=4 THEN
FreeMem(unit,unitSize);
END;
END;
END CloseDiskDevice;
PROCEDURE OpenDiskDevice(devname:CharPtr; dosbase:DosLibraryPtr):UnitDataPtr;
VAR
cname: ARRAY[0..FNSIZE] OF CHAR;
dn:DeviceListPtr;
fssm: FileSysStartupMsgPtr;
dev: EnvironmentPtr;
unit: UnitDataPtr;
BEGIN
dn:=dosbase^.root^.info^.devInfo;
WHILE dn#NIL DO
WITH dn^ DO
IF (type=device) AND (task#NIL) AND (startup#NIL) THEN
BSTRtoStr(name,cname);
IF StrICmp(devname,ADR(cname)) THEN
fssm:=startup;
unit:=AllocMem(SIZE(UnitData)+strlen(devname)+1,
MemReqSet{public,memClear});
IF unit#NIL THEN
unit^.node.name:=CAST(ADDRESS,CAST(LONGINT,unit)+SIZE(UnitData));
StrCpy(unit^.node.name,devname);
unit^.unitSize:=SIZE(UnitData)+strlen(devname)+1;
dev:=fssm^.environment;
unit^.port:=CreatePort(NIL,0);
IF unit^.port#NIL THEN
unit^.request:=CreateStdIO(unit^.port);
IF unit^.request#NIL THEN
BSTRtoStr(fssm^.device,cname);
OpenDevice(ADR(cname),fssm^.unit,unit^.request,fssm^.flags);
IF unit^.request^.error=0 THEN
WITH dev^ DO
unit^.udEnd:=arr[sizeBlock]*4*arr[reservedBlocks];
unit^.buf:=AllocMem(unit^.udEnd,MemReqSet{memClear}+
CAST(MemReqSet,arr[memBufType]));
IF unit^.buf#NIL THEN
unit^.pos:=0;
unit^.udOffset:=arr[lowCyl]*arr[blksPerTrack]*
arr[numHeads]*arr[sizeBlock]*4;
RETURN unit;
ELSE (* no unit^.buf *)
CloseDiskDevice(unit,1);
END; (* if unit^.buf#NIL *)
END; (* with devv^ *)
ELSE (* err opendevice *)
CloseDiskDevice(unit,2);
END; (* if opendevice *)
ELSE (* no request *)
CloseDiskDevice(unit,3);
END; (* if request#nil *)
ELSE (* no port *)
CloseDiskDevice(unit,4);
END; (* if port#nil *)
ELSE (* no memory *)
CloseDiskDevice(unit,5);
END; (* if unit # nil *)
END; (* if stricmp *)
END; (* if type=device *)
END; (* with dn^ *)
dn:=dn^.next;
END; (* WHILE dn#nil *)
RETURN NIL;
END OpenDiskDevice;
(*VAR ptype:ARRAY [0..31] OF CHAR;
PROCEDURE MakeMsg(type:LONGINT);
VAR i:INTEGER;
BEGIN
ptype:='got packet:000000';
FOR i:=16 TO 11 BY -1 DO
ptype[i]:=CHAR(type REM 10+30H);
type:=type/10;
END;
END MakeMsg;*)
(*PROCEDURE MakeVal(type:LONGINT);
VAR i:INTEGER;
BEGIN
ptype:='value: 000000';
FOR i:=12 TO 7 BY -1 DO
ptype[i]:=CHAR(type REM 10+30H);
type:=type/10;
END;
BreakPoint(ADR(ptype));
END MakeVal;
*)
PROCEDURE DosHandler;
VAR actual: LONGINT;
diskname: CharPtr;
diskbuf: ARRAY[0..FNSIZE] OF CHAR;
fh: FileHandlePtr;
UD: UnitDataPtr;
AccessList: List;
DOSBase: DosLibraryPtr;
proc: ProcessPtr;
pkt: DosPacketPtr;
devnode: DeviceListPtr;
mymsg: MessagePtr;
PROCEDURE MakeLock(name:BSTR; mode:LONGINT):FileLockPtr;
VAR f:FileLockPtr; a:POINTER TO FileLock;
BEGIN
a:=AllocMem(SIZE(FileLock),MemReqSet{public,memClear});
IF a#NIL THEN
f:=BPTR(a);
BSTRtoStr(name,diskbuf);
diskname:=ADR(diskbuf);
WHILE diskname^#':' DO INC(diskname) END;
INC(diskname);
WITH f^ DO
access:=mode;
key:=CAST(LONGINT,OpenDiskDevice(diskname,DOSBase));
task:=CAST(MsgPortPtr,CAST(LONGINT,FindTask(NIL))+SIZE(Task));
volume:=devnode;
END;
IF f^.key#NIL THEN
RETURN f;
ELSE
FreeMem(a,SIZE(FileLock));
RETURN NIL
END;
ELSE
RETURN NIL
END;
END MakeLock;
PROCEDURE DeleteLock(l:FileLockPtr):LONGINT;
BEGIN
IF l#NIL THEN
CloseDiskDevice(CAST(UnitDataPtr,l^.key),0);
FreeMem(ADDRESS(l),SIZE(FileLock));
RETURN DOSTRUE
ELSE
RETURN DOSFALSE
END;
END DeleteLock;
TYPE BFileInfoBlockPtr = BPOINTER TO FileInfoBlock;
PROCEDURE Exam(f:FileLockPtr; fib:BFileInfoBlockPtr):LONGINT;
VAR ud:UnitDataPtr;
BEGIN
IF f#NIL THEN
ud:=CAST(UnitDataPtr,f^.key);
WITH fib^ DO
diskKey:=f^.key;
dirEntryType:=-3; (* fileHeader *)
StrCpy(ADR(fileName[1]),ud^.node.name);
fileName[0]:=' ';
protection:=ProtectionFlagSet{delete,execute,script,pure};
entryType:=-3;
size:=ud^.udEnd;
numBlocks:=size/512;
(* date:= *)
comment:=' This is not really a file!';
END;
RETURN DOSTRUE
ELSE
RETURN DOSFALSE
END;
END Exam;
BEGIN
proc:=CAST(ProcessPtr,FindTask(NIL));
IF wbStarted THEN
mymsg:=CAST(MessagePtr,startupMsg);
pkt:=CAST(DosPacketPtr,mymsg^.node.name);
ELSE
pkt:=WaitPacket(proc);
END;
devnode:=CAST(DeviceListPtr,pkt^.arg3); (* hier err, war *4 devptr=BPTR *)
devnode^.task:=ADR(proc^.msgPort);
pkt^.res1:=DOSTRUE;
ReturnPacket(pkt,proc);
DOSBase:=ADR(Dos);
NewList(ADR(AccessList));
LOOP (* forever!! *)
pkt:=WaitPacket(proc);
WITH pkt^ DO
IF type=locateObject THEN (* lock erzeugen *)
res1:=CAST(LONGINT,MakeLock(CAST(BSTR,arg2),arg3));
res2:=objectNotFound; (* falls fehler *)
ELSIF type=freeLock THEN
res1:=DeleteLock(CAST(FileLockPtr,arg1));
res2:=invalidLock;
ELSIF type=examineObject THEN
res1:=Exam(CAST(FileLockPtr,arg1),CAST(BPTR,arg2));
res2:=invalidLock;
ELSIF (type=newFile) OR (type=oldFile) OR (type=readWrite) THEN
fh:=CAST(FileHandlePtr,arg1); (* nicht *4, ist BPTR! *)
fh^.port:=NIL;
BSTRtoStr(CAST(BSTR,arg3),diskbuf);
diskname:=ADR(diskbuf);
WHILE diskname^#':' DO INC(diskname) END;
INC(diskname);
IF (type#oldFile) AND
(FindAccessConflict(AccessList,diskname,exclusiveLock) OR
FindAccessConflict(AccessList,diskname,sharedLock)) THEN
res1:=DOSFALSE;
res2:=objectInUse;
ELSE
UD:=OpenDiskDevice(diskname,DOSBase);
fh^.arg1:=CAST(LONGINT,UD);
IF UD#NIL THEN
IF (type#newFile) AND (DoDeviceCmd(UD,Exec.read) # UD^.udEnd) THEN
res1:=DOSFALSE;
res2:=objectNotFound;
CloseDiskDevice(UD,0);
ELSE
IF type=readWrite THEN
UD^.access:=exclusiveLock
ELSE
UD^.access:=sharedLock
END;
AddTail(ADR(AccessList),ADR(UD^.node));
res1:=DOSTRUE;
END;
ELSE (* fehler beim Öffnen *)
res1:=DOSFALSE;
res2:=objectNotFound;
END;
END;
ELSIF type=ACTIONEND THEN
UD:=CAST(UnitDataPtr,arg1);
Remove(ADR(UD^.node));
CloseDiskDevice(UD,0);
res1:=DOSTRUE;
ELSIF type=read THEN
UD:=CAST(UnitDataPtr,arg1);
actual:=DoDiskCmd(UD,Exec.read,CAST(CharPtr,arg2),arg3);
res1:=actual;
IF actual=DOSTRUE THEN
res2:=deviceNotMounted;
END;
ELSIF type=write THEN
UD:=CAST(UnitDataPtr,arg1);
IF (UD^.access=sharedLock) AND
FindAccessConflict(AccessList,UD^.node.name,exclusiveLock) THEN
res1:=DOSTRUE;
res2:=objectInUse;
ELSE
actual:=DoDiskCmd(UD,Exec.write,CAST(CharPtr,arg2),arg3);
res1:=actual;
IF actual=DOSTRUE THEN
res2:=writeProtected;
END;
END;
ELSIF type=ACTIONSEEK THEN
UD:=CAST(UnitDataPtr,arg1);
actual:=UD^.pos;
CASE arg3 OF
| current:
IF ((actual+arg2)>UD^.udEnd) OR ((actual+arg2)<0) THEN
actual:=DOSTRUE;
ELSE
INC(UD^.pos,arg2);
END;
| beginning:
IF (arg2>UD^.udEnd) OR (arg2<0) THEN
actual:=DOSTRUE;
ELSE
UD^.pos:=arg2;
END;
| end:
IF ((UD^.udEnd+arg2)<0) OR (arg2>0) THEN
actual:=DOSTRUE;
ELSE
UD^.pos:=UD^.udEnd+arg2;
END;
| ELSE (* keine gurus!!!! *)
actual:=DOSTRUE;
END; (* case *)
res1:=actual;
IF actual=DOSTRUE THEN
res2:=seekError;
END;
ELSIF (type=currentVolume) OR (type=flush) THEN
res1:=DOSFALSE;
res2:=0;
ELSIF type=deleteObject THEN
res1:=DOSFALSE;
res2:=deleteProtected;
ELSE (* kennen wir nicht *)
res1:=DOSFALSE;
res2:=actionNotKnown;
END;
END; (* with pkt^ *)
ReturnPacket(pkt,proc);
END; (* endless loop *)
END DosHandler;
BEGIN
TermProcedure(Cleanup);
DosHandler;
END BootHandler.